/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.pdx.cs.guavadata.domain;

import edu.pdx.cs.guavadata.AppData;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.lang.String;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.UUID;

/**
 *
 * @author VuTran
 */
public class Lookup extends Domain {

    private String view;
    private String tableName;

    public Lookup(String view, String tableName) {
        this.view = view;
        this.tableName = tableName;
    }
    
    @Override
    public boolean validate(Object o) {
        if (o == null) return true;
        if (o instanceof UUID) return true;
        return false;
    }

    @Override
    public Object convertString(String s) throws DomainConversionException {
        return UUID.fromString(s);
    }

    @Override
    public Class getNaiveType() {
        return UUID.class;
    }

    @Override
    public String getDBType() {
        return "uniqueidentifier";
    }

    @Override
    public boolean equals(Object obj) {
        return ((obj instanceof Lookup) && (((Lookup) obj).view == this.view) && (((Lookup) obj).tableName == this.tableName));
    }

    @Override
    public int hashCode() {
        return Lookup.class.hashCode() + view.hashCode() * tableName.hashCode();
    }

    @Override
    public String toString() {
        return "InternalLookup: " + this.tableName;
    }

    
    @Override
    public Domain upcast() {
        return new UniqueIdentifier();
    }

    @Override
    public Object upcastValue(Object o) throws Exception {
        return o;
    }

    @Override
    public Domain merge(Domain d) {
        if (this.equals(d)) return this;
        return null;
    }

    @Override
    public boolean isOrdered() {
        return false;
    }

    @Override
    public boolean canContain() {
        return false;
    }

    @Override
    public List<Object> listOutput() {
        ResultSet rs = AppData.fetchAllRows(tableName);

        List<Object> lo = new ArrayList<Object>();
        List<String> columnsFound = new ArrayList<String>();
        try {
            
            
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                String toFind = "<" + rsmd.getColumnName(i) + ">";
                if (view.contains(toFind)) columnsFound.add(rsmd.getColumnName(i));
            }
            
            while (rs.next()) {
                String temp = view;
                for (String s : columnsFound) {
                    temp = temp.replace("<" + s + ">", rs.getObject(this.tableName + "_" + s).toString());
                }
                lo.add(new AnnotatedGuid(UUID.fromString((String) rs.getObject(this.tableName + "_" + "id")), temp));
            }
        } catch (SQLException ex) {
            Logger.getLogger(Lookup.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return lo;
    }
    
    

    @Override
    public Domain clone() {
        return new Lookup(this.tableName, this.view);
    }

    @Override
    public Element ToXml(Document xdoc) {
        Element xe = xdoc.createElement("Domain");
        xe.setAttribute("Type", "Lookup");
        if (view != null) xe.setAttribute("View", view);
        if (tableName != null) xe.setAttribute("TableName", tableName);
        return xe;
    }

    public static Lookup fromElement(Element e) {
        return new Lookup(e.getAttribute("TableName"), e.getAttribute("View"));
    }

    /**
     * @return the view
     */
    public String getView() {
        return view;
    }

    /**
     * @param view the view to set
     */
    public void setView(String view) {
        this.view = view;
    }

    /**
     * @return the tableName
     */
    public String getTableName() {
        return tableName;
    }

    /**
     * @param tableName the tableName to set
     */
    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

}
